HDU 5212 ZZX and Permutations(置换、线段树)

题意:

$给定一个N\le 10^5的置换序列的Cycle Notation,然后现在把括号删掉了$
$现在求一个加上括号的Cycle Notation的原始置换序列$
$但要求输出最大字典序的$

分析:

$稍微懂点置换的思路的都可以看出这个规律:$
$从Cycle Notation中找多个环出来,由于最大字典序$
$找到1的时候,肯定填合法的最大的那个数$
$能填的数就右边第一个,以及左边到自己 没使用过的任意一个$
$看看谁大就填谁,如果是一种直接填,第二种就把这堆数直接成环了$
$对于怎么模拟呢,赛上想多了,线段树上二分写不出,无奈写了二分+线段树T了$
$主要是我自己太纠结于这个已经成环和已经使用的区分了。。导致写法爆炸。。$
$然后队友不懂置换不能给我实质性的帮助,我自己也是逗比,深层次的总结写法能力弱$
$事实上只要动态维护最大值就可以了,用过的从线段树中删除就行了。。$
$至于查询区间,也就是第二种情况,只用维护成环的就好了。。$
$这个只要用set来维护那些成环的区间就好了,每次二分查找一下当前可用的区间$
$这样这个题的代码就非常简单了。。$
$时间复杂度线段树和set都是logn每次,总复杂度O(nlogn)$

代码:

//
//  Created by TaoSama on 2016-05-26
//  Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <cassert>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, a[N], wh[N], ans[N];

#define MP make_pair

struct SegTree {
    int lazy[N << 2], maxv[N << 2];
    void up(int rt) {
        maxv[rt] = max(maxv[rt << 1], maxv[rt << 1 | 1]);
    }
    void down(int rt) {
        if(lazy[rt]) {
            int ls = rt << 1, rs = ls | 1;
            lazy[ls] = lazy[rs] = lazy[rt];
            maxv[ls] = maxv[rs] = lazy[rt] = 0;
        }
    }
    void build(int l, int r, int rt) {
        lazy[rt] = 0;
        if(l == r) {
            maxv[rt] = a[l];
            return;
        }
        int m = l + r >> 1;
        build(l, m, rt << 1);
        build(m + 1, r, rt << 1 | 1);
        up(rt);
    }
    void del(int L, int R, int l, int r, int rt) {
        if(L <= l && r <= R) {
            lazy[rt] = 1;
            maxv[rt] = 0;
            return ;
        }
        int m = l + r >> 1;
        down(rt);
        if(L <= m) del(L, R, l, m, rt << 1);
        if(R > m) del(L, R, m + 1, r, rt << 1 | 1);
        up(rt);
    }
    int query(int L, int R, int l, int r, int rt) {
        if(L <= l && r <= R) return maxv[rt];
        int m = l + r >> 1;
        down(rt);
        int ret = 0;
        if(L <= m) ret = max(ret, query(L, R, l, m, rt << 1));
        if(R > m) ret = max(ret, query(L, R, m + 1, r, rt << 1 | 1));
        return ret;
    }
} T;

int main() {
#ifdef LOCAL
    freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);
    clock_t _ = clock();

    int t; scanf("%d", &t);
    while(t--) {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) scanf("%d", a + i), wh[a[i]] = i;

        T.build(1, n, 1);
        set<pair<int, int> > done;
        memset(ans, 0, sizeof ans);
        for(int i = 1; i <= n; ++i) {
            if(ans[i]) continue;
            int p = wh[i];

            int l = 1, r = min(n, p + 1);
            auto iter = done.lower_bound({p, p});
            if(iter != done.begin()) l = (--iter)->second + 1;

            int maxv = T.query(l, r, 1, n, 1);
            int from = wh[maxv];

            if(from == p + 1) {
                ans[a[p]] = a[from];
                T.del(from, from, 1, n, 1); //delete
            } else {
                //link
                for(int j = from; j < p; ++j) ans[a[j]] = a[j + 1];
                ans[a[p]] = a[from];

                T.del(from, p, 1, n, 1); //delete
                done.insert({from, p}); //maintain the cycled intervals
            }
        }

        for(int i = 1; i <= n; ++i) printf("%d%c", ans[i], " \n"[i == n]);
    }

#ifdef LOCAL
    printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
#endif
    return 0;
}